<script setup lang="ts">
import { RenderingEngine, Types, Enums, metaData } from '@cornerstonejs/core'
import { initDemo } from '@/helpers'
import _ from 'lodash'
import {
  annotation, CrosshairsTool, StackScrollMouseWheelTool
} from '@cornerstonejs/tools'

const { removeAllAnnotations } = annotation.state
import { onMounted, provide, ref, toRef, watch } from 'vue'
import OpButtonGroup from '@/components/OpButtonGroup.vue'
import FourCorner from '@/components/FourCorner.vue'
import { useInitToolGroup } from '@/hooks/useToolGroup'
import { useFourCorner } from '@/hooks/useFourCorner'
import { IMG_OP_NAME, IMG_OP_NAME_RESET, IMG_OP_NOT_TOOL_NAME, OP_TOOLS_MAP } from '@/types/viewSetting'
import { FOUR_CORNER_SHOW_NAME } from '@/types/types'
import { getCTValue } from '@/hooks/getCTValue'

const { ViewportType } = Enums
const { IMAGE_RENDERED, STACK_NEW_IMAGE, VOI_MODIFIED } = Enums.Events
const OpBtns = [IMG_OP_NAME.PAN, IMG_OP_NAME.ZOOM, IMG_OP_NAME.WINDOW, IMG_OP_NAME.SCROLL,
  IMG_OP_NAME.ROTATE, IMG_OP_NAME.LENGTH, IMG_OP_NAME.ANGEL, IMG_OP_NAME.RECT,
  IMG_OP_NAME.FLIP_H, IMG_OP_NAME.FLIP_V, IMG_OP_NAME.INVERT, IMG_OP_NAME.COLOR_MAP,
  IMG_OP_NAME.RESET_CAMERA, IMG_OP_NAME.RESET_PROPERTIES, IMG_OP_NAME.RESET_MEASURE
]

const props = defineProps(['imageIds', 'ids'])

const imageIdsRef = toRef(props, 'imageIds')
let viewport: Types.IStackViewport


const handleNotToolOp = {
  [IMG_OP_NOT_TOOL_NAME.FLIP_H]: () => {
    const { flipHorizontal } = viewport.getCamera()
    viewport.setCamera({ flipHorizontal: !flipHorizontal })
    viewport.render()
  },
  [IMG_OP_NOT_TOOL_NAME.FLIP_V]: () => {
    const { flipVertical } = viewport.getCamera()
    viewport.setCamera({ flipVertical: !flipVertical })
    viewport.render()
  },
  [IMG_OP_NOT_TOOL_NAME.INVERT]: () => {
    const { invert } = viewport.getProperties()
    viewport.setProperties({ invert: !invert })
    viewport.render()
  },
  [IMG_OP_NOT_TOOL_NAME.COLOR_MAP]: (colorMapName = 'hsv') => {
    viewport.setProperties({ colormap: { name: colorMapName } })
    viewport.render()
  }
}

const handleReset = {
  [IMG_OP_NAME_RESET.RESET_CAMERA]: () => {
    viewport.resetCamera()
    renderingEngine.render()
  },
  [IMG_OP_NAME.RESET_PROPERTIES]: () => {
    viewport.resetToDefaultProperties()
    viewport.setProperties({
      colormap: {
        name: 'Grayscale'
      }
    })
    renderingEngine.render()
  },
  [IMG_OP_NAME.RESET_MEASURE]: () => {
    removeAllAnnotations()
    renderingEngine.render()
  }
}

const addEventFlagRef = ref(false)
const initFlagRef = ref(false)

const viewportId = props.ids.viewportId
const renderingEngineId = props.ids.renderingEngineId
const toolsGroupId = props.ids.toolsGroupId
let { toolGroup, activeOp, setActive, addTools2Render } = useInitToolGroup(toolsGroupId, handleReset, handleNotToolOp)

const { cornerVal, updateCornerVal } = useFourCorner([viewportId])

provide('toolGroup', toolGroup)

const initTools = () => {

}

let renderingEngine: RenderingEngine
const renderContainerRef = ref(null)

const initRender = () => {
  renderingEngine = new RenderingEngine(renderingEngineId)
  const viewportInput = {
    viewportId,
    type: ViewportType.STACK,
    element: renderContainerRef.value,
    defaultOptions: {
      background: <Types.Point3>[0.2, 0, 0.2]
    }
  }
  renderingEngine.enableElement(viewportInput)
  viewport = <Types.IStackViewport>renderingEngine.getViewport(viewportId)
}

const listenEvent = () => {
  renderContainerRef.value.addEventListener(IMAGE_RENDERED, ((
    evt: Types.EventTypes.ImageRenderedEvent
  ) => {
    const imageId = viewport.getCurrentImageId()
    const obj = metaData.get('imgInfoModule', imageId)
    updateCornerVal(viewportId, obj)
  }) as EventListener)


  renderContainerRef.value.addEventListener(STACK_NEW_IMAGE, ((
    evt: Types.EventTypes.StackNewImageEvent
  ) => {
    updateCornerVal(viewportId, {
      [FOUR_CORNER_SHOW_NAME.INDEX]: evt.detail.imageIdIndex
    })
    if (!addEventFlagRef.value) {
      renderContainerRef.value.addEventListener('mousemove', _.throttle(evt => {
        const rect = renderContainerRef.value.getBoundingClientRect()
        const canvasPos = <Types.Point2>[
          Math.floor(evt.clientX - rect.left),
          Math.floor(evt.clientY - rect.top)
        ]
        const imageId = viewport.getCurrentImageId()
        const img = metaData.get('imagePlaneModule', imageId)
        const worldPos = viewport.canvasToWorld(canvasPos)
        const imagePosition = img.imagePositionPatient
        const pixelSpacing = img.pixelSpacing
        const columns = ((worldPos[0] - imagePosition[0]) / pixelSpacing[0]).toFixed(0)
        const rows = ((worldPos[1] - imagePosition[1]) / pixelSpacing[1]).toFixed(0)
        const ctValue = getCTValue(viewport.getImageData(), worldPos) || -1000
        updateCornerVal(viewportId, {
          [FOUR_CORNER_SHOW_NAME.X]: rows,
          [FOUR_CORNER_SHOW_NAME.Y]: columns,
          [FOUR_CORNER_SHOW_NAME.CT]: ctValue
        })
      }, 50))
      addEventFlagRef.value = true
    }
  }) as EventListener)


  renderContainerRef.value.addEventListener(VOI_MODIFIED, ((
    evt: Types.EventTypes.VoiModifiedEvent
  ) => {
    const { lower, upper } = evt.detail.range
    updateCornerVal(viewportId, {
      [FOUR_CORNER_SHOW_NAME.WW]: upper - lower,
      [FOUR_CORNER_SHOW_NAME.WL]: (upper + lower) / 2
    })
  }) as EventListener)
}


async function run() {
  // Init Cornerstone and related libraries
  await initDemo()
  initRender()
  initTools()
  initFlagRef.value = true
  addTools2Render(viewportId, renderingEngineId)
  listenEvent()
}

watch([imageIdsRef, initFlagRef], ([newIds, newFlag]) => {
  if (newIds && newIds.length > 0 && newFlag) {
    render(imageIdsRef.value)
  }
})

function render(imageIds) {
  updateCornerVal(viewportId, {
    [FOUR_CORNER_SHOW_NAME.TOTAL]: imageIds.length
  })
  viewport.setStack(imageIds)
  renderingEngine.renderViewport(viewportId)
}


onMounted(() => {
  run()
})
const showFourCornerRef = ref(true)

</script>


<template>
  <div class="w-full mb-[20px]">
    <OpButtonGroup @setActive="setActive" :active="activeOp" :op-btns="OpBtns" />
  </div>
  <div class="w-full h-[500px] bg-transparent flex justify-center">
    <div class="w-[600px] h-full bg-transparent  relative" ref="renderContainerRef">
      <four-corner v-if="showFourCornerRef" :fourCornerVal="cornerVal[viewportId]" />
    </div>
  </div>
</template>

<style scoped>

</style>
